/**
******************************************************************************************
* @file NannyBearBrain.c
* @brief Management of all classes which use bricklets.
* @date 29 mars 2015
* @author Benjamin Lancinot
*****************************************************************************************/
/* COPYRIGHT ****************************************************************************
*****************************************************************************************
* Copyright (c) 2015, Audrey LOISEAU and Benjamin LANCINOT.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
*    list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************************************/

#include "NannyBearBrain.h"

/*******************************************************************************************
* PROTOYPES
********************************************************************************************/

void NannyBearBrain_destroyUtilities(NannyBearBrain*);

void NannyBearBrain_destroy(NannyBearBrain**);

void NannyBearBrain_linkObserversToSubjects(NannyBearBrain *);

void NannyBearBrain_run(NannyBearBrain *);

/*******************************************************************************************
* FUNCTIONS
********************************************************************************************/

/**
 * @brief Constructor
 * @return Pointer to a new NannyBearBrain
 **/
NannyBearBrain* NannyBearBrain_create(){
	NannyBearBrain* This = (NannyBearBrain *) malloc(sizeof(*This));

	//The ip connection for link bricklets and brick @Tinkerforge
	IPConnection ipcon;
	ipcon_create(&ipcon);
	This->ipcon = ipcon;

        //Init functions
        This->carryOn = TRUE;
	This->run = NannyBearBrain_run;
	This->destroy = NannyBearBrain_destroy;

        //Create objects which command bricklets
	This->electrician = Electrician_create(ipcon);
	This->mercureLover = MercureLover_create(ipcon);
        This->humidityTester = HumidityTester_create(ipcon);
	This->soundEngineer = SoundEngineer_create(ipcon);
        This->lcdProjector = LCDProjector_create(ipcon);
        This->connectionState = ConnectionState_create();
        This->ioBouncer = IOBouncer_create(ipcon);

	if(ipcon_connect(&This->ipcon, HOST, PORT) < 0) {
		fprintf(stderr, "Could not connect\n");
		return NULL;
	}

        //Create callback for bricklet and init the threshold of it
	This->electrician->initThreshold(This->electrician);
	This->mercureLover->initThreshold(This->mercureLover);
	This->humidityTester->initThreshold(This->humidityTester);
	This->soundEngineer->initThreshold(This->soundEngineer);
        This->ioBouncer->initIo(This->ioBouncer);

        //Create command for designe pattern Commend
        This->cmdTab[0] = ChangeDimThreshold_create(&This->electrician->luminosityThreshold[0]);
        This->cmdTab[1] = ChangeBrightThreshold_create(&This->electrician->luminosityThreshold[1]);
        This->cmdTab[2] = ChangeSoundThreshold_create(&This->soundEngineer->noiseThreshold);
        This->cmdTab[3] = ResetAverage_create(This->mercureLover->averageMaker);
        This->cmdTab[4] = ResetAverage_create(This->humidityTester->averageMaker);
        This->cmdTab[5] = ChangeAllLeds_create(This->ioBouncer->ledsHandyman);
        This->cmdTab[6] = ChangeLedByLed_create(This->ioBouncer->ledsHandyman);
        This->cmdTab[7] = ChangeAnimation_create(This->ioBouncer->ledsHandyman);
        This->cmdTab[8] = ChangeMusic_create(This->ioBouncer->discJockey);

        This->cmdTabSize = 9;

	return This;

}


/**
 * @brief Destroy all of the components of NannyBearBrain
 * @param This Pointer to the wanted NannyBearBrain
 **/
void NannyBearBrain_destroyUtilities(NannyBearBrain* This){

        //Destroy all objects which belonged to NannyBearBrain
        This->electrician->destroy(&This->electrician);
        This->humidityTester->destroy(&This->humidityTester);
	This->mercureLover->destroy(&This->mercureLover);
	This->soundEngineer->destroy(&This->soundEngineer);
        This->lcdProjector->destroy(&This->lcdProjector);
        This->connectionState->destroy(&This->connectionState);
        This->ioBouncer->destroy(&This->ioBouncer);
        ipcon_destroy(&This->ipcon);
        int i;
         for (i = 0; i < This->cmdTabSize; i++) {
		 This->cmdTab[i]->destroy(&This->cmdTab[i]);
	 }

}


/**
 * @brief Destructor
 * @param This Double pointer to the wanted NannyBearBrain
 **/
void NannyBearBrain_destroy(NannyBearBrain** This){
        NannyBearBrain_destroyUtilities(* This);
       	if (*This) {
		free(*This);
		*This = NULL;
	}
}


/**
 * @brief Relevant to the observer pattern, subject in NannyBearBrain are registered with goods observers
 * @param This Pointer to the wanted NannyBearBrain
 **/
void NannyBearBrain_linkObserversToSubjects(NannyBearBrain *This){
        //link observers which have to work without connection
        This->mercureLover->registerObserver(This->mercureLover, This->lcdProjector->observer);
        This->mercureLover->mercureController->registerObserver(This->mercureLover->mercureController, This->lcdProjector->observer);
	This->mercureLover->averageMaker->registerObserver(This->mercureLover->averageMaker, This->lcdProjector->observer);

        This->humidityTester->registerObserver(This->humidityTester, This->lcdProjector->observer);
        This->humidityTester->humidityController->registerObserver(This->humidityTester->humidityController, This->lcdProjector->observer);
        This->humidityTester->averageMaker->registerObserver(This->humidityTester->averageMaker, This->lcdProjector->observer);

        //notify firsts datas
        This->mercureLover->subject->notifyObservers(This->mercureLover->subject);
        This->humidityTester->subject->notifyObservers(This->humidityTester->subject);
        This->mercureLover->mercureController->subject->notifyObservers(This->mercureLover->mercureController->subject);
        This->humidityTester->humidityController->subject->notifyObservers(This->humidityTester->humidityController->subject);
	This->mercureLover->averageMaker->subject->notifyObservers(This->mercureLover->averageMaker->subject);
	This->humidityTester->averageMaker->subject->notifyObservers(This->humidityTester->averageMaker->subject);

}


/**
 * @brief Background task for running bricklets. This task run all the time until user ask to switch off NannyBear
 * @param This Pointer to the wanted NannyBearBrain
 **/
void NannyBearBrain_run(NannyBearBrain *This){

	printf("nannyRun\n");
        //Run the thread of displaying on lcd

        NannyBearBrain_linkObserversToSubjects(This);
        This->lcdProjector->start(This->lcdProjector,&This->carryOn);

        //Wait for people press button off on lcd projector (cf nannyIsAlive)
        while(This->carryOn == TRUE);

        This->lcdProjector->stop(This->lcdProjector);

}
